#ifndef GapText_First
#define GapText_First
#ifdef __GNUG__
#pragma interface
#endif

#include "Text.h"

class RegularExp;
class GapTextIter;

extern const int
	cShrinkFactor,
	cMaxOutput;

//---- GapText -----------------------------------------------------------------

class GapText: public Text  {
public:
	MetaDef(GapText);

	GapText(int s= cTextInitCap, Font *fd= gSysFont);
	GapText(const char *buf, int len= -1, Font *fd= gSysFont);
	GapText(const byte *buf, int len= -1, Font *fd= gSysFont);
	~GapText();
	void InitNew();
	void GapTextInit(const char *buf, int len, Font *fd, int cap);

	//---- editing
	void CopyInStr(byte *str, int strsize, int from, int to);
	void ReplaceRange(int from, int to, Text *tsrc, int sfrom, int sto);

	//---- accessing
	const char *AsString();
	byte& operator[](int i);
	int Size();
	int Search(RegularExp *rex, int *nMatched, int start= 0,
				int range= cMaxInt, bool dir= cSearchForward);

	//---- iterators
	TextIter *MakeIterator(int from= 0, int to= cMaxInt, void *placement= 0);

	//---- TextPainter access
	byte *GetLineAccess(byte **buf, int from, int to);

	//---- TextReader access
	void AddChar(int at, byte b);

	//---- input/output
	OStream& PrintOn(OStream&);
	IStream& ReadFrom(IStream&);
	OStream& PrintOnAsPureText(OStream &s);
	IStream& ReadFromAsPureText(IStream &s, long sizeHint= -1);

protected:
	byte CharAt(int i);
	void Terminate();
	Text *MakeScratchText(byte *buf, int size);

private:
	friend GapTextIter;

	int size;                               // size of allocated memory
	int length;                             // length of text
	int part1len;                           // length of text before gap
	int part2len;                           // redundant (for meta-info)
	int gaplen;                             // length of gap
	byte *body;                             // access to text before gap
	byte *part2body;                        // access to text behind gap
	byte *body2;                            // redundant (for meta-info)

	void Update(int l);
	void Init(int l, Font *fd);
	void Expand(int to= 0, int moveto= cMaxInt);
	void Shrink(int to= 0);
	void MoveGap(int to);
	void CopyTo(byte *dst, int from, int to);
	bool HighWaterMark(int n);
	bool LowWaterMark();
	void CheckPtr(byte *ptr);
};

inline bool GapText::HighWaterMark(int n)
	{ return (body == 0) || (gaplen <= n); }

inline bool GapText::LowWaterMark()
	{ return (size / 5) > length; }

inline byte GapText::CharAt(int i)
	{ return (i < part1len ? body : part2body)[i]; }

//---- GapTextIter -------------------------------------------------------------

class GapTextIter: public TextIter {
	int nextFontChange;
	byte escape;
	GapText *st;
	CharStyle *sp;

	bool TestFontChange(int at, CharStyle *&sp);
	int GraphicSize(int at, LineDesc *l);
	byte CharAt(int i);
	bool TestFontChange(CharStyle *&sp);
	bool TestVisualMark(int at, int ch);
public:
	GapTextIter(Text *s, int from= 0, int to= cMaxInt);
	void Reset(Text *s, int from= 0, int to= cMaxInt);
	int operator()(int *width= 0, LineDesc *ld= 0);
	int Token(int *width, LineDesc*); // returns next token with its extent
};

inline byte GapTextIter::CharAt(int i)
	{ return st->CharAt(i); }

inline bool GapTextIter::TestFontChange(CharStyle *&s)
{
	if (ce == nextFontChange) {
		nextFontChange= st->GetNextFontChange(ce, s);
		return TRUE;
	} else
		return FALSE;
}

inline bool GapTextIter::TestVisualMark(int at, int ch)
	{ return (bool) (ch == escape && st->IsVisualMark(at)); }

#endif
